
#pragma once

#include "core.h"
#include "vec.h"

namespace Blox
{

	class Matrix
	{
	public:

		Matrix ( ) { }

		//static inline void Add ( Vec & r, Vec const & a, Vec const & b ) { r.x=a.x+b.x; r.y=a.y+b.y; r.z=a.z+b.z; }
		//static inline void Sub ( Vec & r, Vec const & a, Vec const & b ) { r.x=a.x-b.x; r.y=a.y-b.y; r.z=a.z-b.z; }
		//static inline void Mul ( Vec & r, Vec const & a, Vec const & b ) { r.x=a.x*b.x; r.y=a.y*b.y; r.z=a.z*b.z; }
		//static inline void Scale ( Vec & r, Vec const & a, float s ) { r.x=a.x*s; r.y=a.y*s; r.z=a.z*s; }
		//static inline void Cross ( Vec & r, Vec const & a, Vec const & b ) { }
		//static inline float Dot ( Vec const & a, Vec const & b ) { return (a.x*b.x)+(a.y*b.y)+(a.z*b.z); }
		//static inline float MagSqr ( Vec const & a ) { return Dot(a,a); }
		//static inline float Mag ( Vec const & a ) { return FSqrt(MagSqr(a)); }
		//static inline void Min ( Vec & r, Vec const & a, Vec const & b ) { r.x=FMin(a.x,b.x); r.y=FMin(a.y,b.y); r.z=FMin(a.z,b.z); }
		//static inline void Max ( Vec & r, Vec const & a, Vec const & b ) { r.x=FMax(a.x,b.x); r.y=FMax(a.y,b.y); r.z=FMax(a.z,b.z); }
		//static inline void Lerp ( Vec & r, Vec const & a, Vec const & b, float t ) { r.x=FLerp(a.x,b.x,t); r.y=FLerp(a.y,b.y,t); r.z=FLerp(a.z,b.z,t); }
		//static inline float Norm ( Vec & r, Vec const & a ) { float d = Mag(a); Scale(r,a,1.0f/d); return d; }

		//// Basic [Add,Sub,Scale]
		//inline Vec operator+ ( Vec const & a ) const { Vec r; Add(r,*this,a); return r; }
		//inline Vec operator- ( Vec const & a ) const { Vec r; Sub(r,*this,a); return r; }
		//inline Vec operator* ( float const s ) const { Vec r; Scale(r,*this,s); return r; }
		//inline Vec& operator+= ( Vec const & a ) { Add(*this,*this,a); return *this; }
		//inline Vec& operator-= ( Vec const & a ) { Sub(*this,*this,a); return *this; }
		//inline Vec& operator*= ( float const s ) { Scale(*this,*this,s); return *this; }

		//// Special [Dot,Cross]
		//inline float operator* ( Vec const & a ) const { return Dot(*this,a); }
		//inline Vec operator^ ( Vec const & a ) const { Vec r; Cross(r,*this,a); return r; }

		//// Self Functions [Norm]
		inline void Identity ( ) {  }

		inline Vec const & GetRow ( u32 uRow ) const { return *((Vec const *)(&v[uRow][0])); }
		inline Vec4 const & GetRow4 ( u32 uRow ) const { return *((Vec4 const *)(&v[uRow][0])); }

		inline void SetRow ( u32 uRow, Vec const & val, float w = 1.0f ) { ((Vec &)(v[uRow][0])) = val; v[uRow][3] = w; }
		inline void SetRow ( u32 uRow, Vec4 const & val ) { *((Vec4 const *)(&v[uRow][0])); }

		//////////////////////////////////////////////////////////////////////////
		inline Vec4 const & GetTranslation4 ( ) const { return GetRow4(ROW_TRANSLATE); }
		inline Vec const & GetTranslation ( ) const { return GetRow(ROW_TRANSLATE); }
		inline Vec const & GetX ( ) const { return GetRow(ROW_X); }
		inline Vec const & GetY ( ) const { return GetRow(ROW_Y); }
		inline Vec const & GetZ ( ) const { return GetRow(ROW_Z); }

		inline void SetTranslation ( Vec const & val ) { SetRow( ROW_TRANSLATE, val ); }


		union
		{
			struct
			{
				float _00, _01, _02, _03;
				float _10, _11, _12, _13;
				float _20, _21, _22, _23;
				float _30, _31, _32, _33;
			};
			float	v[4][4];
			float	f[16];
		};

	private:
		enum
		{
			ROW_X=0,
			ROW_Y,
			ROW_Z,
			ROW_TRANSLATE
		};
	};


}
